package nl.weeaboo.sh.editor.area;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.LinkedList;
import java.util.List;

import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

import nl.weeaboo.sh.level.Level;
import nl.weeaboo.sh.model.TileModel;
import nl.weeaboo.sh.model.TileModel.Solidity;
import timon.common.components.BigPopupCombo;
import timon.common.components.DirectSpinner;
import timon.common.components.IconListCellRenderer;
import timon.common.components.property.PropertyModel;
import timon.common.components.property.PropertyPanel;
import timon.common.components.property.editor.ComboPropertyEditor;

@SuppressWarnings("serial")
public class TileEditor extends JPanel {

	private TileModel selectedTile;
	private List<ActionListener> listeners;
	
	private JComponent mainPanel;
	private PropertyPanel propertyPanel;
	private PropertyModel propertyModel;
	private JCheckBox slopedCheck;
	private JSpinner h0Spinner;
	private JSpinner h1Spinner;

	private ComboPropertyEditor solidityEditor;
	
	public TileEditor() {
		listeners = new LinkedList<ActionListener>();
		
		propertyPanel = new PropertyPanel();
		
		JComboBox solidityCombo = new BigPopupCombo(TileModel.Solidity.values());
		solidityCombo.setRenderer(new IconListCellRenderer() {
			public String getLabelFor(Object value) {
				return ((Solidity)value).name();
			}
			public Image getImageFor(Object object) {
				return null;
			}
		});
		solidityEditor = new ComboPropertyEditor(solidityCombo);
		
		setLayout(new BorderLayout(5, 5));
		add(mainPanel = createMainPanel(), BorderLayout.CENTER);
		
		mainPanel.setVisible(false);
	}
	public void dispose() {
		propertyPanel.dispose();
	}
	
	//Functions	
	protected JComponent createMainPanel() {
		int ts = Level.tileSize;
		
		slopedCheck = new JCheckBox("Sloped?");		
		slopedCheck.setEnabled(false);
		slopedCheck.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent e) {
				if (selectedTile != null) {
					h0Spinner.setEnabled(slopedCheck.isSelected());
					h1Spinner.setEnabled(slopedCheck.isSelected());
				}
			}
		});
		
		ChangeListener heightSpinnerListener = new ChangeListener() {
			public void stateChanged(ChangeEvent e) {
				if (selectedTile != null) {
					if (h0Spinner.isEnabled()) selectedTile.setHeight0(((Integer)h0Spinner.getValue()).byteValue());
					if (h1Spinner.isEnabled()) selectedTile.setHeight1(((Integer)h1Spinner.getValue()).byteValue());
					slopedCheck.setSelected(selectedTile != null && selectedTile.isSloped());	
				}
			}
		};
		
		
		h0Spinner = new DirectSpinner(new SpinnerNumberModel(ts, 0, ts, 1));
		h0Spinner.addChangeListener(heightSpinnerListener);
		//h0Spinner.setEnabled(false);
		
		h1Spinner = new DirectSpinner(new SpinnerNumberModel(ts, 0, ts, 1));
		h1Spinner.addChangeListener(heightSpinnerListener);
		//h1Spinner.setEnabled(false);
		
		JPanel slopeBottomPanel = new JPanel(new GridLayout(1, 4, 5, 5));
		slopeBottomPanel.add(new JLabel("h0"));
		slopeBottomPanel.add(h0Spinner);
		slopeBottomPanel.add(new JLabel("h1"));
		slopeBottomPanel.add(h1Spinner);
		
		JPanel slopePanel = new JPanel(new GridLayout(0, 1, 5, 5));
		slopePanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		slopePanel.add(slopedCheck);
		slopePanel.add(slopeBottomPanel);
		
		JPanel panel = new JPanel(new BorderLayout(5, 5));
		panel.add(propertyPanel, BorderLayout.CENTER);
		panel.add(slopePanel, BorderLayout.SOUTH);
		panel.setPreferredSize(new Dimension(150, 250));
		return panel;
	}
	
	public void addRoomListener(ActionListener l) {
		listeners.add(l);
	}
	public void removeRoomListener(ActionListener l) {
		listeners.remove(l);
	}
	protected void onTileChanged() {
		ActionEvent ae = new ActionEvent(selectedTile, 0, "");
		ActionListener al[] = listeners.toArray(new ActionListener[listeners.size()]);
		for (ActionListener l : al) {
			l.actionPerformed(ae);
		}
	}

	//Getters
	public TileModel getSelectedTile() {
		return selectedTile;
	}
	
	//Setters
	public void setSelectedTile(TileModel model) {
		if (selectedTile != model) {		
			selectedTile = model;

			mainPanel.setVisible(selectedTile != null);			
			
			//slopedCheck.setEnabled(selectedTile != null);
			slopedCheck.setSelected(selectedTile != null && selectedTile.isSloped());
			h0Spinner.setEnabled(false);
			h1Spinner.setEnabled(false);
			
			propertyModel = new PropertyModel();
			if (selectedTile != null) {
				propertyModel.addProperty("TileModel.solidity", "Solidity", selectedTile.getSolidity(), Solidity.class);				
				propertyModel.addProperty("TileModel.climbable", "Climbable", selectedTile.isClimbable(), Boolean.class);
				propertyModel.addProperty("TileModel.bulletReflecting", "Bullet Reflecting", selectedTile.isBulletReflecting(), Boolean.class);
				propertyModel.addProperty("TileModel.wallJumpable", "Wall-Jumpable", selectedTile.isWallJumpable(), Boolean.class);
				propertyModel.addProperty("TileModel.water", "Water Tile", selectedTile.isWater(), Boolean.class);
				propertyModel.addProperty("TileModel.friction", "Friction", selectedTile.getFriction(), Integer.class);
				propertyModel.addProperty("TileModel.hp", "HP", selectedTile.getHp(), Integer.class);
				propertyModel.addProperty("TileModel.damage", "Damage", selectedTile.getDamage(), Integer.class);
				
				propertyModel.setEditor("TileModel.solidity", solidityEditor);

				h0Spinner.setValue(selectedTile.getHeight0());
				h1Spinner.setValue(selectedTile.getHeight1());
				h0Spinner.setEnabled(true);
				h1Spinner.setEnabled(true);
			} else {
				h0Spinner.setValue(0);				
				h1Spinner.setValue(0);				
			}
			propertyPanel.setModel(propertyModel);									
			propertyModel.addPropertyListener(new PropertyModelListener(selectedTile));
		}
	}
	
	//Inner Classes
	private class PropertyModelListener implements PropertyChangeListener {
		
		private final TileModel selectedTile;
		
		public PropertyModelListener(TileModel selectedTile) {
			this.selectedTile = selectedTile;
		}
		
		public void propertyChange(PropertyChangeEvent event) {
			if (selectedTile == null) {
				return;
			}
			
			String pname = event.getPropertyName();
			if ("TileModel.solidity".equals(pname)) {
				selectedTile.setSolidity((Solidity)event.getNewValue());
			} else if ("TileModel.climbable".equals(pname)) {
				selectedTile.setClimbable((Boolean)event.getNewValue());
			} else if ("TileModel.bulletReflecting".equals(pname)) {
				selectedTile.setBulletReflecting((Boolean)event.getNewValue());
			} else if ("TileModel.wallJumpable".equals(pname)) {
				selectedTile.setWallJumpable((Boolean)event.getNewValue());
			} else if ("TileModel.water".equals(pname)) {
				selectedTile.setWater((Boolean)event.getNewValue());
			} else if ("TileModel.friction".equals(pname)) {
				selectedTile.setFriction(((Integer)event.getNewValue()).byteValue());
			} else if ("TileModel.hp".equals(pname)) {
				selectedTile.setHp(((Integer)event.getNewValue()).shortValue());
			} else if ("TileModel.damage".equals(pname)) {
				selectedTile.setDamage(((Integer)event.getNewValue()).shortValue());
			}
			onTileChanged();
		}
	}

}
